package com.jvm;

import org.apache.catalina.loader.WebappClassLoader;

import java.io.FileInputStream;
import java.lang.reflect.Method;

/**
 * @Author:zxh
 * @Description: 自定义类加载器
 * @Date: 2021/3/6
 * @Modified By:
 */
public class MyClassLoaderTest {
    static class MyClassLoad extends ClassLoader {
        private String classpath;

        public MyClassLoad(String classpath) {
            this.classpath = classpath;
        }

        private byte[] loadByte(String name) throws Exception {
            name = name.replaceAll("\\.", "/");
            FileInputStream fis = new FileInputStream(classpath + "/" + name + ".class");
            int len = fis.available();
            byte[] data = new byte[len];
            fis.read(data);
            fis.close();
            return data;
        }

        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] bytes = loadByte(name);
                //defineClass 将一个字节数组转为Class对象，这个字节数组是class文件读取后最终的字节数组
                return defineClass(name, bytes, 0, bytes.length);
            } catch (Exception e) {
                e.printStackTrace();
                throw new ClassNotFoundException();
            }
        }

    }

    public static void main(String[] args) throws Exception {
         // WebappClassLoader  Tomcat打破双亲委派机制 WebappClassLoader重写了findClass()方法

        // 初始化自定义类加载器，会先初始化父类ClassLoader，其中会把自定义类加载器的父加载器设置为应用程序类加载器AppClassLoader
        // D:/test
        MyClassLoad myClassLoad = new MyClassLoad("/Users/uf205281/Downloads/001-收集箱/tuling");
        //D盘创建 test/com/tuling/jvm 几级目录，将User类的复制类User1.class丢入该目录
        Class<?> aClass = myClassLoad.loadClass("com.jvm.User1");
        // Class<?> aClass = myClassLoad.loadClass("java.lang.String");
        Object newInstance = aClass.newInstance();
        Method method = aClass.getDeclaredMethod("sout", null);
        method.invoke(newInstance, null);
        System.out.println(aClass.getClassLoader().getClass().getName());

        // 无用的类，java.lang.class对象没有任何地方被引用。
        // 如果user对象被GC回收，那么对应的class对象也被GC回收
         Class.forName("com.jvm.User1");// 相当于拿到类的对象a1，
        // 拿到类的对象a1可以进行反射。反射生成实例
        // Object o = a1.newInstance();

    }
}
